package com.github.gaojh.starter.eureka.client;

import cn.hutool.core.util.StrUtil;
import com.github.gaojh.config.Environment;
import com.github.gaojh.ioc.IocUtil;
import com.github.gaojh.ioc.annotation.Bean;
import com.github.gaojh.ioc.annotation.Configuration;
import com.github.gaojh.starter.ServerFace;
import com.netflix.appinfo.ApplicationInfoManager;
import com.netflix.appinfo.EurekaInstanceConfig;
import com.netflix.appinfo.InstanceInfo;
import com.netflix.appinfo.MyDataCenterInstanceConfig;
import com.netflix.appinfo.providers.EurekaConfigBasedInstanceInfoProvider;
import com.netflix.config.DynamicPropertyFactory;
import com.netflix.discovery.DefaultEurekaClientConfig;
import com.netflix.discovery.DiscoveryClient;
import com.netflix.discovery.EurekaClient;
import com.netflix.discovery.EurekaClientConfig;
import org.apache.commons.configuration.AbstractConfiguration;

import java.util.Iterator;

/**
 * @author gaojh
 * @since 2020/4/11
 */
@Configuration
public class EurekaClientStarter implements ServerFace {


    protected ApplicationInfoManager applicationInfoManager;

    private EurekaClient eurekaClient;

    public EurekaClientStarter() {
        if (!Environment.me().containsKey("eureka.port")) {
            Environment.me().put("eureka.port", "" + Environment.me().getPort());
        }
        if (!Environment.me().containsKey("eureka.name")) {
            Environment.me().put("eureka.name", Environment.me().getString("flying.application.name"));
        }
        DynamicPropertyFactory.initWithConfigurationSource(new XConfigure());
    }

    @Bean
    public EurekaInstanceConfig getEurekaInstanceConfig() {
        return new FlyingEurekaInstanceConfig();
    }

    @Bean
    public ApplicationInfoManager getApplicationInfoManager(EurekaInstanceConfig eurekaInstanceConfig) {
        InstanceInfo instanceInfo = new EurekaConfigBasedInstanceInfoProvider(eurekaInstanceConfig).get();
        ApplicationInfoManager applicationInfoManager = new ApplicationInfoManager(eurekaInstanceConfig, instanceInfo);
        applicationInfoManager.setInstanceStatus(InstanceInfo.InstanceStatus.STARTING);
        return applicationInfoManager;
    }

    @Bean("eurekaClient")
    public DiscoveryClient eurekaClient(ApplicationInfoManager applicationInfoManager) {
        EurekaClientConfig eurekaClientConfig = new DefaultEurekaClientConfig();
        return new DiscoveryClient(applicationInfoManager, eurekaClientConfig);
    }

    @Override
    public boolean start() {
        applicationInfoManager = IocUtil.getBean(ApplicationInfoManager.class);
        applicationInfoManager.setInstanceStatus(InstanceInfo.InstanceStatus.UP);
        eurekaClient = IocUtil.getBean(DiscoveryClient.class, "eurekaClient");
        return true;
    }

    @Override
    public boolean stop() {
        if (applicationInfoManager != null) {
            applicationInfoManager.setInstanceStatus(InstanceInfo.InstanceStatus.DOWN);
        }
        if (eurekaClient != null) {
            eurekaClient.shutdown();
        }
        return true;
    }

    public static class XConfigure extends AbstractConfiguration {

        @Override
        public boolean isEmpty() {
            return false;
        }

        @Override
        public boolean containsKey(String key) {
            return Environment.me().containsKey(key);
        }

        @Override
        public Object getProperty(String key) {
            return Environment.me().get(key);
        }

        @Override
        public Iterator<String> getKeys() {
            return Environment.me().keys().iterator();
        }

        @Override
        protected void addPropertyDirect(String key, Object value) {
            Environment.me().put(key, key);
        }

    }


    public static class FlyingEurekaInstanceConfig extends MyDataCenterInstanceConfig {

        @Override
        public String getInstanceId() {
            String instanceId = super.getInstanceId();
            if (StrUtil.isBlank(instanceId)) {
                return getIpAddress() + ":" + getVirtualHostName() + ":" + getNonSecurePort();
            }
            return instanceId;
        }

        @Override
        public String getHostName(boolean refresh) {
            if (Environment.me().containsKey("server.hostname")) {
                return Environment.me().getString("server.hostname");
            }
            return super.getHostName(refresh);
        }
    }
}
